package com.koron.operation.classes.shift.service.impl;


import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.koron.bean.base.Response;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.operation.classes.shift.bean.po.ClassesWorkCompletion;
import com.koron.operation.classes.shift.bean.query.WorkFeignQuery;
import com.koron.operation.classes.shift.feign.OrderFeignService;
import com.koron.operation.classes.shift.feign.TicketFeignService;
import com.koron.operation.classes.shift.mapper.ClassesWorkCompletionMapper;
import com.koron.operation.classes.shift.service.ClassesWorkCompletionService;
import lombok.SneakyThrows;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * 工作完成情况(ClassesWorkCompletion)表服务实现类
 *
 * @author jzp
 * @since 2021-10-27 18:36:23
 */
@Service
public class ClassesWorkCompletionServiceImpl implements ClassesWorkCompletionService {

    @Autowired
    private OrderFeignService orderFeignService;

    @Autowired
    private TicketFeignService ticketFeignService;

    private final ExecutorService service = Executors.newFixedThreadPool(5);

    /**
     * 通过ID查询单条数据
     */
    @Override
    @TaskAnnotation("getById")
    public ClassesWorkCompletion getById(SessionFactory factory, String id) {
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.selectById(id);
    }

    /**
     * 查询所有数据
     */
    @Override
    @TaskAnnotation("list")
    public List<ClassesWorkCompletion> list(SessionFactory factory, ClassesWorkCompletion classesWorkCompletion) {
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.selectList(classesWorkCompletion);
    }

    /**
     * 1. 查询值班人在班次结束之前创建的所有作业，即班次结束时间 > 工作创建时间
     * 2. 筛选未完成的
     * 2.1. 筛选未完成状态的
     * 2.2. 如果有工作预计结束时间的话，去掉预计结束时间在班次开始时间之前的，即去掉班次开始时间 > 工作预计结束时间
     * 3. 筛选已完成的
     * 3.1. 筛选已完成状态的
     * 3.2. 筛选出改值班时间范围内完成的工作，即班次开始时间 < 工作实际结束时间
     */
    @SneakyThrows
    @Override
    public List<ClassesWorkCompletion> getFeignByCondition(WorkFeignQuery query) {
        String currDs = ThreadLocalContext.get().getCurrDs();
        List<String> staffs = query.getStaffs();
        if (CollectionUtils.isEmpty(staffs) || currDs == null || Objects.equals(ThreadLocalContext.get().getCurrDs(), "_default")) {
            return new ArrayList<>();
        }
        Date startDate = query.getDates().get(0);
        String endTime = DateFormatUtils.format(query.getDates().get(1), "yyyy-MM-dd HH:mm");
        List<ClassesWorkCompletion> workCompletions = Collections.synchronizedList(new ArrayList<>());
        CountDownLatch latch = new CountDownLatch(5);    // 定义5个计数个数

        // 1. 查询检修申请单
        service.execute(() -> {
            try {
                Response<Object> appRes = orderFeignService.appList(staffs, endTime);
                addWork(workCompletions, appRes, startDate, this::fromAppJson);
            } finally {
                latch.countDown();    // 计数减一
                ThreadLocalContext.clear(); // 清除tl
            }
        });

        // 2. 查询普通工单
        service.execute(() -> {
            try {
                Response<Object> orderRes = orderFeignService.orderList(staffs, endTime);
                addWork(workCompletions, orderRes, startDate, this::fromOrderJson);
            } finally {
                latch.countDown();    // 计数减一
                ThreadLocalContext.clear(); // 清除tl
            }
        });

        // 3. 查询巡视工单
        service.execute(() -> {
            try {
                Response<Object> patrolRes = orderFeignService.orderList(staffs, endTime);
                addWork(workCompletions, patrolRes, startDate, this::fromPatrolJson);
            } finally {
                latch.countDown();    // 计数减一
                ThreadLocalContext.clear(); // 清除tl
            }
        });

        // 4. 查询操作票
        service.execute(() -> {
            try {
                Response<Object> opTicketRes = ticketFeignService.opTicketList(staffs, endTime);
                addWork(workCompletions, opTicketRes, startDate, this::fromOpTicketJson);
            } finally {
                latch.countDown();    // 计数减一
                ThreadLocalContext.clear(); // 清除tl
            }
        });

        // 5. 查询工作票
        service.execute(() -> {
            try {
                Response<Object> workTicketRes = ticketFeignService.workTicketList(staffs, endTime);
                addWork(workCompletions, workTicketRes, startDate, this::fromWorkTicketJson);
            } finally {
                latch.countDown();    // 计数减一
                ThreadLocalContext.clear(); // 清除tl
            }
        });
        latch.await();
        workCompletions.sort(Comparator.comparing(ClassesWorkCompletion::getWorkType));
        return workCompletions;
    }

    /**
     * 新增数据
     */
    @Override
    @TaskAnnotation("save")
    public boolean save(SessionFactory factory, ClassesWorkCompletion classesWorkCompletion) {
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.insertOrUpdate(classesWorkCompletion) > 0;
    }

    @Override
    @TaskAnnotation("saveBatch")
    public boolean saveBatch(SessionFactory factory, List<ClassesWorkCompletion> workCompletions) {
        if (CollectionUtils.isEmpty(workCompletions)) {
            return false;
        }
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.insertOrUpdateBatch(workCompletions) > 0;
    }

    /**
     * 修改数据
     */
    @Override
    @TaskAnnotation("update")
    public boolean update(SessionFactory factory, ClassesWorkCompletion classesWorkCompletion) {
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.update(classesWorkCompletion) > 0;
    }

    /**
     * 通过主键删除数据
     */
    @Override
    @TaskAnnotation("deleteBatchIds")
    public boolean deleteBatchIds(SessionFactory factory, List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }
        ClassesWorkCompletionMapper mapper = factory.getMapper(ClassesWorkCompletionMapper.class);
        return mapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 通过recordId删除数据
     */
    @Override
    @TaskAnnotation("removeByRecordId")
    public boolean removeByRecordId(SessionFactory factory, String recordId) {
        if (StringUtils.isEmpty(recordId)) {
            return false;
        }
        ClassesWorkCompletion classesWorkCompletion = new ClassesWorkCompletion();
        classesWorkCompletion.setRecordId(recordId);
        List<ClassesWorkCompletion> list = list(factory, classesWorkCompletion);

        return deleteBatchIds(factory, list.stream().map(ClassesWorkCompletion::getId).collect(Collectors.toList()));
    }

    private void addWork(List<ClassesWorkCompletion> workCompletions, Response<Object> response, Date startDate, BiFunction<JSONObject, Date, ClassesWorkCompletion> function) {
        Assert.notNull(response.getData(), response.getDescription());
        JSONArray jsonArray = JSONArray.parseArray(JSONArray.toJSONString(response.getData()));
        for (int i = 0; i < jsonArray.size(); i++) {
            ClassesWorkCompletion workCompletion = function.apply(jsonArray.getJSONObject(i), startDate);
            if (workCompletion != null) {
                workCompletions.add(workCompletion);
            }
        }
    }

    /**
     * 解析检修申请单的json数据
     */
    private ClassesWorkCompletion fromAppJson(JSONObject jsonObject, Date startDate) {
        Integer status = jsonObject.getInteger("status");
        /*
         * 设置状态
         *  未完成
         *      0,1,2,3
         *      班次开始时间 <= 工作预计结束时间
         *  已完成：
         *      4
         *      班次开始时间 <= 工作实际结束时间
         */
        ClassesWorkCompletion workCompletion = new ClassesWorkCompletion();
        // 预计结束时间
        Date endTime = jsonObject.getDate("endTime");
        // 实际结束时间
        Date factEndTime = jsonObject.getDate("factEndTime");

        if (Arrays.asList(0, 1, 2, 3).contains(status)) {
            // 预计结束时间，去掉预计结束时间在班次开始时间之前的
            if (endTime != null && endTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(0);
            workCompletion.setCompletionTime(new Date());
        } else if (status == 4 && factEndTime != null) {
            if (factEndTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(1);
            workCompletion.setCompletionTime(factEndTime);
        } else {
            return null;
        }

        workCompletion.setWorkId(jsonObject.getString("id"));
        workCompletion.setWorkType("application");
        workCompletion.setWorkCode(jsonObject.getString("code"));
        workCompletion.setWorkContent(jsonObject.getString("title"));

        return workCompletion;
    }

    /**
     * 解析普通工单的json数据
     */
    private ClassesWorkCompletion fromOrderJson(JSONObject jsonObject, Date startDate) {
        String status = jsonObject.getString("status");
        /*
         * 设置状态
         *  编码order_all_status
         *  未完成
         *      1,2,3,4,5,6
         *      班次开始时间 <= 工作预计结束时间
         *  已完成：
         *      ARCHIVED
         *      班次开始时间 <= 工作实际结束时间
         */
        ClassesWorkCompletion workCompletion = new ClassesWorkCompletion();
        // 预计结束时间
        Date endTime = jsonObject.getDate("endTime");
        // 实际结束时间
        Date factEndTime = jsonObject.getDate("factEndTime");

        if ("ARCHIVED".equals(status) && factEndTime != null) {
            if (factEndTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(1);
            workCompletion.setCompletionTime(factEndTime);
        } else {
            // 预计结束时间，去掉预计结束时间在班次开始时间之前的
            if (endTime != null && endTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(0);
            workCompletion.setCompletionTime(new Date());
        }

        workCompletion.setWorkId(jsonObject.getString("id"));
        workCompletion.setWorkType(jsonObject.getString("orderType"));
        workCompletion.setWorkCode(jsonObject.getString("code"));
        workCompletion.setWorkContent(jsonObject.getString("title"));

        return workCompletion;
    }

    /**
     * 解析巡视工单的json数据
     */
    private ClassesWorkCompletion fromPatrolJson(JSONObject jsonObject, Date startDate) {
        String status = jsonObject.getString("status");
        /*
         * 设置状态
         *  未完成
         *      1,2
         *      班次开始时间 <= 工作预计结束时间
         *  已完成：
         *      3
         *      班次开始时间 <= 工作实际结束时间
         */
        ClassesWorkCompletion workCompletion = new ClassesWorkCompletion();
        // 预计结束时间
        Date endTime = jsonObject.getDate("planEndTime");
        // 实际结束时间
        Date factEndTime = jsonObject.getDate("factEndTime");
        if (Arrays.asList("WAIT_PATROL", "IN_PATROL").contains(status)) {
            // 预计结束时间，去掉预计结束时间在班次开始时间之前的
            if (endTime != null && endTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(0);
            workCompletion.setCompletionTime(new Date());
        } else if ("END_PATROL".equals(status) && factEndTime != null) {
            if (factEndTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(1);
            workCompletion.setCompletionTime(factEndTime);
        } else {
            return null;
        }

        workCompletion.setWorkId(jsonObject.getString("id"));
        workCompletion.setWorkType("patrol");
        workCompletion.setWorkCode(jsonObject.getString("code"));
        workCompletion.setWorkContent(jsonObject.getString("title"));

        return workCompletion;
    }

    /**
     * 解析操作票的json数据
     */
    private ClassesWorkCompletion fromOpTicketJson(JSONObject jsonObject, Date startDate) {
        Integer status = jsonObject.getInteger("status");

        ClassesWorkCompletion workCompletion = new ClassesWorkCompletion();
        // 实际结束时间
        Date factEndTime = jsonObject.getDate("endTime");

        if (Arrays.asList(0, 1, 2).contains(status)) {
            workCompletion.setStatus(0);
            workCompletion.setCompletionTime(new Date());
        } else if (status == 4 && factEndTime != null) {
            if (factEndTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(1);
            workCompletion.setCompletionTime(factEndTime);
        } else {
            return null;
        }

        workCompletion.setWorkId(jsonObject.getString("id"));
        workCompletion.setWorkType("operationTicket");
        workCompletion.setWorkCode(jsonObject.getString("code"));
        workCompletion.setWorkContent(jsonObject.getString("context"));

        return workCompletion;
    }

    /**
     * 解析工作票的json数据
     */
    private ClassesWorkCompletion fromWorkTicketJson(JSONObject jsonObject, Date startDate) {
        ClassesWorkCompletion workCompletion = new ClassesWorkCompletion();
        // 实际结束时间
        Date factEndTime = jsonObject.getDate("realEndTIme");
        // 预计结束时间
        Date endTime = jsonObject.getDate("estimatedEndTime");

        if (factEndTime == null) {
            // 预计结束时间，去掉预计结束时间在班次开始时间之前的
            if (endTime != null && endTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(0);
            workCompletion.setCompletionTime(new Date());
        } else {
            if (factEndTime.before(startDate)) {
                return null;
            }
            workCompletion.setStatus(1);
            workCompletion.setCompletionTime(factEndTime);
        }

        workCompletion.setWorkId(jsonObject.getString("id"));
        workCompletion.setWorkType("workTicket");
        workCompletion.setWorkCode(jsonObject.getString("code"));
        workCompletion.setWorkContent(jsonObject.getString("title"));

        return workCompletion;
    }

}
